#include "StdAfx.h"
#include "DShowAudio.h"

#include <math.h>

#include "backstage_runtime_audio_DirectShowPlayer.h"

CDShowAudio g_dshowAudio;

CDShowAudio::CDShowAudio(void)
:m_bLoop(FALSE)
,m_iPlay(State_Stopped)
{
}

CDShowAudio::~CDShowAudio(void)
{
}

HRESULT CDShowAudio::init()
{
	HRESULT ret;
	ret=m_graphBuilder.CreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER);
	if(SUCCEEDED(ret))
	{
		ret=m_graphBuilder->QueryInterface(&m_mediaControl);
		if(SUCCEEDED(ret))
		{
			ret=m_graphBuilder->QueryInterface(&m_mediaSeeking);
			if(SUCCEEDED(ret))
			{
				ret=m_graphBuilder->QueryInterface(&m_basicAudio);
				if(SUCCEEDED(ret))
				{
					ret=m_graphBuilder->QueryInterface(&m_mediaEvent);
// 					if(SUCCEEDED(ret))
// 						if(g_hWnd)
// 							setNotifyWindow(g_hWnd);
				}
			}
		}
	}
	return ret;
}

void CDShowAudio::setNotifyWindow( HWND hWnd )
{
	if(m_mediaEvent)
		m_mediaEvent->SetNotifyWindow((OAHWND)hWnd,MSG_DSHOW_EVENT,NULL);
}

void CDShowAudio::release()
{
	if(m_mediaControl)
		m_mediaControl.Release();
	if(m_mediaSeeking)
		m_mediaSeeking.Release();
	if(m_basicAudio)
		m_basicAudio.Release();
	if(m_graphBuilder)
		m_graphBuilder.Release();
}

void CDShowAudio::stop()
{
	if ( m_iPlay && m_mediaControl )
		if(SUCCEEDED(m_mediaControl->Stop())) 
			m_iPlay = State_Stopped;
}

int CDShowAudio::open(const TCHAR *fname )
{
	m_bLoop=TRUE;
	if(init()<0)
		return -1;

	LONGLONG ret;
	if(FAILED(m_graphBuilder->RenderFile(fname,NULL)) ||
		m_mediaSeeking==NULL ||
		FAILED(m_mediaSeeking->IsFormatSupported(&TIME_FORMAT_MEDIA_TIME)) ||
		FAILED(m_mediaSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME)) ||
		FAILED(m_mediaSeeking->GetDuration(&ret)))
	{
		release();
		return -1;
	}
	return ret/10000;
}

void CDShowAudio::start()
{
	if(m_mediaControl)
		if(SUCCEEDED(m_mediaControl->Run()))
			m_iPlay=State_Running;
}

void CDShowAudio::pause()
{
	if(m_iPlay==State_Running && m_mediaControl)
		if(SUCCEEDED(m_mediaControl->Pause()))
			m_iPlay=State_Paused;
}

BOOL CDShowAudio::setVolume( float x )
{
	if(m_basicAudio)
	{
		double v;
		if(x==0.0)
			v=-10000.0;
		else
			v=log10(x)*20.0*100.0;
		return SUCCEEDED(m_basicAudio->put_Volume(v));
	}
	return FALSE;
}

BOOL CDShowAudio::seek( int p )
{
	if(m_mediaSeeking)
	{
		LONGLONG pos=10000i64*p;
		return SUCCEEDED(m_mediaSeeking->SetPositions(&pos,AM_SEEKING_AbsolutePositioning,NULL,0));
	}
	return FALSE;
}

int CDShowAudio::tell()
{
	LONGLONG pos;
	if(m_mediaSeeking &&
		SUCCEEDED(m_mediaSeeking->GetPositions(&pos,NULL)))
		return pos/10000;

	return -1;
}

BOOL CDShowAudio::setRate( float r )
{
	double rate;
	if(m_mediaSeeking &&
		SUCCEEDED(m_mediaSeeking->GetRate(&rate)))
		return SUCCEEDED(m_mediaSeeking->SetRate(r));

	return FALSE;
}

void CDShowAudio::onNotify()
{
	if(m_mediaEvent && m_mediaSeeking)
	{
		long code;
		LONG_PTR p1,p2;

		while(SUCCEEDED(m_mediaEvent->GetEvent(&code,&p1,&p2,0)))
		{
			m_mediaEvent->FreeEventParams(code,p1,p2);
			if(code==EC_COMPLETE)
			{
				LONGLONG cur=0;
				if(m_bLoop)
					m_mediaSeeking->SetPositions(&cur,AM_SEEKING_AbsolutePositioning,NULL,0);
				else
					stop();
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
JNIEXPORT void JNICALL Java_backstage_runtime_audio_DirectShowPlayer_initNative
(JNIEnv *, jclass)
{
	CoInitialize(NULL);
}

JNIEXPORT jint JNICALL Java_backstage_runtime_audio_DirectShowPlayer_openNative
(JNIEnv *env, jobject, jstring fname)
{
	const jchar *s=env->GetStringChars(fname,NULL);
	jint ret=g_dshowAudio.open((const TCHAR *)s);
	env->ReleaseStringChars(fname,s);
	return ret;
}

JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_closeNative
(JNIEnv *, jobject)
{
	g_dshowAudio.stop();
	g_dshowAudio.release();
	return TRUE;
}

JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_startNative
(JNIEnv *, jobject)
{
	g_dshowAudio.start();
	return TRUE;
}

JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_stopNative
(JNIEnv *, jobject)
{
	g_dshowAudio.pause();
	return TRUE;
}

JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_setVolumeNative
(JNIEnv *, jobject, jfloat x)
{
	return g_dshowAudio.setVolume(x);
}

JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_setLoopNative
(JNIEnv *, jobject, jboolean l)
{
	g_dshowAudio.m_bLoop=l;
	return TRUE;
}

JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_seekNative
(JNIEnv *, jobject, jint p)
{
	return g_dshowAudio.seek(p);
}

JNIEXPORT jint JNICALL Java_backstage_runtime_audio_DirectShowPlayer_getCurrentTimeNative
(JNIEnv *, jobject)
{
	return g_dshowAudio.tell();
}

JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_setRateNative
(JNIEnv *, jobject, jfloat r)
{
	return g_dshowAudio.setRate(r);
}
